using System;
using System.Collections.Generic;
using opt.Analysis.Graph;
using opt.Analysis.Graph.ControlFlowGraph;
using opt.Analysis.Graph.ControlFlowGraph.ControlFlowGraphVisitor;
using CLELCore.Assembly.CLELInstructions;

namespace opt.Analysis.Set
{
	public class ReachingDefinitions
	{
		private List<BitSet> gen;
		private List<BitSet> kill;
		private ControlFlowGraph<CFGArcInfo,CFGNodeInfo> cfg;

		private List<BitSet> in_set;
		private List<BitSet> out_set;

		public List<BitSet> In
		{
			get
			{
				return in_set;
			}
		}
		public List<BitSet> Out
		{
			get
			{
				return out_set;
			}
		}

		public ReachingDefinitions(List<CLELInstruction> code,GenKill gk,ControlFlowGraph<CFGArcInfo,CFGNodeInfo> cfg)
		{
			if(code == null)
				throw new ArgumentException("Code cannot be null");
			if(gk == null)
				throw new ArgumentException("Gen/Kill cannot be null");
			if(cfg == null)
				throw new ArgumentException("Control Flow Graph cannot be null");

			gen = gk.Gen;
			kill = gk.Kill;
			this.cfg = cfg;

			in_set = new List<BitSet>();
			out_set = new List<BitSet>();
			int i;
			int count = code.Count;
			for(i = 0;i < count;i++)
			{
				in_set.Add(new BitSet());
				out_set.Add(new BitSet());
			}
			
			CalculateReachingDefinitions();
		}

		private void CalculateReachingDefinitions()
		{
			ReachingDefinitionsVisit visit = new ReachingDefinitionsVisit(gen,kill,in_set,out_set);
			ControlFlowGraphVisitor<CFGArcInfo,CFGNodeInfo> visitor = new ControlFlowGraphVisitor<CFGArcInfo,CFGNodeInfo>(cfg);

			do
			{
				visit.Changed = false;
				visitor.Accept(visit);
			
				/*	
				Console.WriteLine("IN");
				for(int i = 0;i < in_set.Count;i++)
				{
					List<Int32> num = in_set[i].GetNumberSet();
					Console.Write(i+": ");
					for(int k = 0;k < num.Count;k++)
						Console.Write(num[k]+" ");
					Console.WriteLine();
				}
				*/

			} while(visit.Changed);
		}
	}
}
